/*
 The surface-physics project: http:// code.google.com/p/surface-physics/
 Adds real world physics based on the Bullet physics engine, to bases in the Orbiter space
 flight simulation software.

 Written by Abhijit Nandy
 License : Apache License 2.0

 Bump_VesselCollisionDefCache.cpp
 Bump_VesselCollisionDefCache management implementation.


*/


/* Class declaration */
#include "Bump_VesselCollisionDefCache.h"

#include "Bump_BulletBase.h"


/**
 * Constructor for this class
 *
 */
Bump_VesselCollisionDefCache::Bump_VesselCollisionDefCache()
{


}


/**
 * Destructor, should destroy the allocated VesselCollisionDef
 *
 * TODO: Add support for writing back dirty defs to file after renaming old file
 */
Bump_VesselCollisionDefCache::~Bump_VesselCollisionDefCache()
{
	// Delete all allocated VesselDefs & the compound shape inside
	// Before deleting compound shape delete all its constituent shapes too

	for(mCacheIter = mCache.begin();  mCacheIter != mCache.end(); ++mCacheIter){

		 VesselCollisionDef *pVesselCollDef = mCacheIter->second;

		// Delete wheel shapes
		if (pVesselCollDef->frontWheelShape)
			delete pVesselCollDef->frontWheelShape;

		if (pVesselCollDef->backWheelShape)
			delete pVesselCollDef->backWheelShape;

		// Delete the chassis shapes
		for (int i = 0; i < pVesselCollDef->numShapes; ++i) {
			char *p = (char*)pVesselCollDef->chassisShapeFileNames[i];
			if (p)
				delete p;
			delete pVesselCollDef->chassisShapes[i];
		}


		// Delete the VesselDef
		delete (pVesselCollDef);
	}


}


/**
 * Return / add vessel collision definition
 *
 */
VesselCollisionDef*
Bump_VesselCollisionDefCache::getVesselCollisionDef(char *strVesselClassName)
{

	std::string s(strVesselClassName);
	mCacheIter = mCache.find(s);
	if (mCacheIter != mCache.end()) {
		// Got the vessel definition in the cache
		oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: Found in Collision Cache",	strVesselClassName);

		return mCacheIter->second;
	}

	// Didnt get it in cache, read in the definition, put it in the cache, return the pointer.

	char strFileName[256];
	sprintf(strFileName, "Bump/%s.txt", strVesselClassName);
	mPhysicsFile = oapiOpenFile(strFileName, FILE_IN , ROOT);

	if (!mPhysicsFile) {
		oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: ERROR : VesselDef file '%s' could \
				not be opened",	strFileName);
		return NULL;
	}

	//oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: File '%s' opened !", strFileName);

	VesselCollisionDef* pVesselCollDef = new VesselCollisionDef();

	// Assemble the collision definition in steps

	// First set defaults for mandatory properties
	setDefaults(pVesselCollDef);

	char *line;
	while (oapiReadScenario_nextline (mPhysicsFile, line)) {

		//Skip blank lines and comments
		if(strlen(line) == 0 || line[0] == ';')
			continue;

		if (!_strnicmp (line, "Type", 4)) {  // custom item
			char type[256];
			sscanf (line+4, "%s", type);
			if (strcmp(type, "Vehicle") == 0)
				pVesselCollDef->collMeshType = CMT_VEHICLE;
			else
				pVesselCollDef->collMeshType = CMT_MESH;
		}
		else if (strcmp(line, "BEGIN_PROPERTIES") == 0) {

			//oapiReadScenario_nextline (mPhysicsFile, line);

			// Read the properties
			if (readProperties(pVesselCollDef)) {
				oapiCloseFile(mPhysicsFile, FILE_IN);
				oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: ERROR Could not read properties from \
						VesselDef file '%s'", strFileName);
				delete pVesselCollDef;
				return NULL;
			}
		}
		else if (strcmp(line, "BEGIN_CHASSIS") == 0) {

			//oapiReadScenario_nextline (mPhysicsFile, line);

			// Read the chassis details
			if (readChassis(pVesselCollDef)) {
				oapiCloseFile(mPhysicsFile, FILE_IN);
				oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: ERROR Could not read properties from \
						VesselDef file '%s'", strFileName);
				delete pVesselCollDef;
				return NULL;
			}
		}
	}


	// Put into cache (a map)
	mCache.insert(CollisionDefCache::value_type(s, pVesselCollDef));

	/*oapiWriteLogV("Bump_VesselCollisionDefCache::getVesselCollisionDef: Added VesselDef for vessel class '%s'",
			strVesselClassName);*/

	oapiCloseFile(mPhysicsFile, FILE_IN);
	return pVesselCollDef;
}


/**
 * Read the chassis shapes section and create/add them to the compound shape in the
 * vessel def structure
 *
 * Allowed shapes :
 * ConvexHull
 * Box
 * Cylinder - in progress
 * Sphere - in progress
 * Cone - in progress
 * Capsule - in progress
 *
 * Note : Case-insensitive compare is used
 * TODO: The shape parameters list will later be alterable interactively
 * TODO: Add scaling parameters to use with local scaling esp. memory eff. with convex hull
 *
 */
int
Bump_VesselCollisionDefCache::readChassis(VesselCollisionDef* pVesselCollDef)
{
	//--------------------------- Chassis ----------------------------

	pVesselCollDef->chassisLocalHeight = 0.; //1.2; // Height of chassis above vehicle origin

	char *line;
	pVesselCollDef->numShapes = 0;

	while (oapiReadScenario_nextline (mPhysicsFile, line)) {

		if (strlen(line) == 0 || line[0] == ';')	//Skip blank lines and comments
			continue;

		float x, y, z, rx, ry, rz;
		int i = pVesselCollDef->numShapes;

		// Stop if maximum allowed chassis shapes read
		if (i == VesselCollisionDef::MAX_SHAPES)
			break;

		// Null the file name
		pVesselCollDef->chassisShapeFileNames[i] = NULL;

		// Start check shapes
		if (!_strnicmp (line, "ConvexHull", 10)) {
			char fileName[256];
			sscanf (line+10, "%s %f %f %f %f %f %f", fileName, &x, &y, &z, &rx, &ry, &rz);

			if (!isValid(x, y, z, rx, ry, rz, 0., 0., 0.))
				continue;

			// Collision shapes
			pVesselCollDef->chassisShapes[i] = new btConvexHullShape();
			loadMsh(fileName, (btConvexHullShape*)pVesselCollDef->chassisShapes[i]);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
									 x, y, z,
									 rx, ry, rz);

			pVesselCollDef->chassisShapeFileNames[i] = new char[256];
			strcpy(pVesselCollDef->chassisShapeFileNames[i], fileName);
			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "Box", 3)) {
			btScalar length, width, height;
			sscanf (line+3, "%f %f %f %f %f %f %f %f %f", &x, &y, &z, &rx, &ry, &rz,
					&length, &width, &height);

			if (!isValid(x, y, z, rx, ry, rz, length, width, height))
				continue;

			pVesselCollDef->chassisShapes[i] = new btBoxShape(btVector3(length/2.f, width/2.f, height/2.f));

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "CylinderX", 9)) {
			btScalar radius, height;
			sscanf (line+9, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height,0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btCylinderShapeX(btVector3(radius, radius, height/2.f));

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "CylinderY", 9)) {
			btScalar radius, height;
			sscanf (line+9, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btCylinderShape(btVector3(radius, radius, height/2.f));

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "CylinderZ", 9)) {
			btScalar radius, height;
			sscanf (line+9, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btCylinderShapeZ(btVector3(radius, radius, height/2.f));

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "Sphere", 6)) {
			btScalar radius;
			sscanf (line+6, "%f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius);

			if (!isValid(x, y, z, rx, ry, rz, radius, 0., 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btSphereShape(radius);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "ConeX", 5)) {
			btScalar radius, height;
			sscanf (line+5, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btConeShapeX(radius, height);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "ConeY", 5)) {
			btScalar radius, height;
			sscanf (line+5, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btConeShape(radius, height);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "ConeZ", 5)) {
			btScalar radius, height;
			sscanf (line+5, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btConeShapeZ(radius, height);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}
		else if (!_strnicmp (line, "Capsule", 7)) {
			btScalar radius, height;
			sscanf (line+7, "%f %f %f %f %f %f %f %f",
					&x, &y, &z, &rx, &ry, &rz, &radius, &height);

			if (!isValid(x, y, z, rx, ry, rz, radius, height, 0.))
				continue;

			pVesselCollDef->chassisShapes[i] = new btCapsuleShape(radius, height/2.f);

			setTransform(pVesselCollDef->chassisShapeTransforms[i],
						 x, y, z,
						 rx, ry, rz);

			pVesselCollDef->numShapes = i + 1;
		}


	}


	return 0;
}


/**
 * Read the properties section into a vessel definition
 *
 * Note : Case-insensitive compare is used
 *
 */
int
Bump_VesselCollisionDefCache::readProperties(VesselCollisionDef* pVesselCollDef)
{
	char *line;

	while (oapiReadScenario_nextline (mPhysicsFile, line)) {

		if (!_strnicmp (line, "FrontWheelRadius", 16)) {  // custom item
			sscanf (line+16, "%f", &pVesselCollDef->frontWheelRadius);
		}
		else if (!_strnicmp (line, "BackWheelRadius", 15)) {  // custom item
			sscanf (line+15, "%f", &pVesselCollDef->backWheelRadius);
		}
		else if (!_strnicmp (line, "FrontWheelWidth", 15)) {  // custom item
			float wheelWidth;
			sscanf (line+15, "%f", &wheelWidth);
			pVesselCollDef->frontWheelHalfWidth = wheelWidth / 2.f;
		}
		else if (!_strnicmp (line, "BackWheelWidth", 14)) {  // custom item
			float wheelWidth;
			sscanf (line+14, "%f", &wheelWidth);
			pVesselCollDef->backWheelHalfWidth = wheelWidth / 2.f;
		}
		else if (!_strnicmp (line, "FrontWheelFriction", 18)) {  // custom item
			sscanf (line+18, "%f", &pVesselCollDef->frontWheelFriction);
		}
		else if (!_strnicmp (line, "BackWheelFriction", 17)) {  // custom item
			sscanf (line+17, "%f", &pVesselCollDef->backWheelFriction);
		}
		else if (!_strnicmp (line, "FrontSuspensionStiffness", 25)) {  // custom item
			sscanf (line+25, "%f", &pVesselCollDef->frontSuspensionStiffness);
		}
		else if (!_strnicmp (line, "BackSuspensionStiffness", 24)) {  // custom item
			sscanf (line+24, "%f", &pVesselCollDef->backSuspensionStiffness);
		}
		else if (!_strnicmp (line, "FrontSuspensionDamping", 22)) {  // custom item
			sscanf (line+22, "%f", &pVesselCollDef->frontSuspensionDamping);
		}
		else if (!_strnicmp (line, "BackSuspensionDamping", 21)) {  // custom item
			sscanf (line+21, "%f", &pVesselCollDef->backSuspensionDamping);
		}
		else if (!_strnicmp (line, "FrontSuspensionCompression", 25)) {  // custom item
			sscanf (line+25, "%f", &pVesselCollDef->frontSuspensionCompression);
		}
		else if (!_strnicmp (line, "BackSuspensionCompression", 24)) {  // custom item
			sscanf (line+24, "%f", &pVesselCollDef->backSuspensionCompression);
		}
		else if (!_strnicmp (line, "FrontSuspensionRestLength", 25)) {  // custom item
			sscanf (line+25, "%f", &pVesselCollDef->frontSuspensionRestLength);
		}
		else if (!_strnicmp (line, "BackSuspensionRestLength", 24)) {  // custom item
			sscanf (line+24, "%f", &pVesselCollDef->backSuspensionRestLength);
		}
		else if (!_strnicmp (line, "RollInfluence", 13)) {  // custom item
			sscanf (line+13, "%f", &pVesselCollDef->rollInfluence);
		}
		else if (!_strnicmp (line, "WheelCount", 10)) {  // custom item
			sscanf (line+10, "%d", &pVesselCollDef->numWheels);
		}
		else if (!_strnicmp (line, "WheelInfo", 9)) {  // custom item
			int wheelIndex, wheelMeshIndex, wheelMeshGroupIndex, wheelStrutMeshGroupIndex;
			float x, y, z;

			sscanf (line+9, "%d %d %d %d %f %f %f",
					&wheelIndex, &wheelMeshIndex, &wheelMeshGroupIndex, &wheelStrutMeshGroupIndex,
					&x, &y, &z);
			--wheelIndex;
			pVesselCollDef->wheelMeshIndex = wheelMeshIndex;
			pVesselCollDef->wheelMeshGroupIndex[wheelIndex] = wheelMeshGroupIndex;
			pVesselCollDef->wheelStrutMeshGroupIndex[wheelIndex] = wheelStrutMeshGroupIndex,
			pVesselCollDef->wheelMeshGroupCenter[wheelIndex] = _V(x, y, z);
			pVesselCollDef->isWheelInfoSet[wheelIndex] = true;
		}
		else if (!_strnicmp (line, "InitialVehicleHeight", 20)) {  // custom item
			sscanf (line+20, "%f", &pVesselCollDef->initialVehicleHeight);
		}
		else if (strlen(line) == 0 || line[0] == ';')	//Skip blank lines and comments
			continue;
		else
			break;	// either END_PROPERTIES hit or an unrecognized property, exit for both.

	}

	// Wheel Shapes
	pVesselCollDef->frontWheelShape = new btCylinderShapeX(btVector3(pVesselCollDef->frontWheelHalfWidth,
																	 pVesselCollDef->frontWheelRadius,
																	 pVesselCollDef->frontWheelRadius));
	pVesselCollDef->backWheelShape  = new btCylinderShapeX(btVector3(pVesselCollDef->backWheelHalfWidth,
														   	   	     pVesselCollDef->backWheelRadius,
														   	   	     pVesselCollDef->backWheelRadius));




	return 0;
}


/**
 * Sets defaults for mandatory parameters
 *
 */
int
Bump_VesselCollisionDefCache::setDefaults(VesselCollisionDef* pVesselCollDef)
{

	pVesselCollDef->collMeshType = CMT_VEHICLE;

	// -----------------Wheel parameters -------------------------------

	// These are set in readProperties() to account for user input - can't be changed after creation
	pVesselCollDef->frontWheelShape = NULL;
	pVesselCollDef->backWheelShape  = NULL;

	pVesselCollDef->frontWheelRadius = 0.24;
	pVesselCollDef->backWheelRadius = 0.5f;
	pVesselCollDef->frontWheelHalfWidth = 0.2f;	 // actual width is 2.364(twice)
	pVesselCollDef->backWheelHalfWidth = 0.2f;	 // actual width is 2.364(twice)
	pVesselCollDef->frontWheelFriction = 1500;
	pVesselCollDef->backWheelFriction = 1500;
	//pVesselCollDef->frontWheelConnectionPoint = 0.f;
	pVesselCollDef->rightIndex = 0;
	pVesselCollDef->upIndex = 1;
	pVesselCollDef->forwardIndex = 2;
	pVesselCollDef->wheelDirection.setValue(0,-1,0);
	pVesselCollDef->wheelAxle.setValue(-1,0,0);

	pVesselCollDef->frontConnectionHeight = 0.;
	pVesselCollDef->backConnectionHeight = 0.;

	// Suspension parameters
	pVesselCollDef->frontSuspensionStiffness = 170.f;
	pVesselCollDef->frontSuspensionDamping = 150.0f;  //this may need to be increased for the DG
	pVesselCollDef->frontSuspensionCompression = 0.f;
	pVesselCollDef->frontSuspensionRestLength = 2.3f;

	pVesselCollDef->backSuspensionStiffness = 170.f;
	pVesselCollDef->backSuspensionDamping = 150.0f;  //this may need to be increased for the DG
	pVesselCollDef->backSuspensionCompression = 0.f;
	pVesselCollDef->backSuspensionRestLength = 2.3f;

	pVesselCollDef->rollInfluence = 0.08f;// 1.0f;

	// Orbiter animation info
	pVesselCollDef->numWheels = 3;
	pVesselCollDef->wheelMeshIndex = 0;

	// It is mandatory to supply all wheel info, these flags help to check this
	for (int i=0; i<VesselCollisionDef::MAX_WHEELS; ++i) {
		pVesselCollDef->isWheelInfoSet[i] = false;
	}

	// Number of chassis shapes is 0 by default, must be caught
	pVesselCollDef->numShapes = 0;

	// THIS MUST BE 0 - Otherwise kinematic vehicle wont report collisions as wheels wont be
	// touching ground - its not a vehicle deactivation issue AT ALL !!
	pVesselCollDef->initialVehicleHeight = 0.;


	return 0;
}


/**
 * Prints all vessel definitions
 *
 */
void
Bump_VesselCollisionDefCache::printCache(void)
{
	int i = 0;

	oapiWriteLogV("============ CollDef Cache has %d items =============", mCache.size());

	for(mCacheIter = mCache.begin();  mCacheIter != mCache.end(); ++mCacheIter){
		oapiWriteLogV("------ CollDef %d (%s) -------", i, (mCacheIter->first).c_str());
		printVesselCollisionDef(mCacheIter->second);
		++i;
	}

	oapiWriteLog("======================================================");

}

inline void
Bump_VesselCollisionDefCache::printVesselCollisionDef(VesselCollisionDef* pVesselCollDef)
{
	// Iterate through all properties
	oapiWriteLogV("Type: %s",
			(pVesselCollDef->collMeshType == CMT_VEHICLE ? "Vehicle Collider" : "Mesh Collider"));


	// -----------------Wheel parameters -------------------------------

	// These are set in readProperties() to account for user input - can't be changed after creation
	if (pVesselCollDef->frontWheelShape)
		oapiWriteLogV("FrontWheelShape: %s", pVesselCollDef->frontWheelShape->getName() );
	if (pVesselCollDef->backWheelShape)
		oapiWriteLogV("BackWheelShape: %s", pVesselCollDef->backWheelShape->getName() );

	oapiWriteLogV("FrontWheelRadius: %f", pVesselCollDef->frontWheelRadius);
	oapiWriteLogV("BackWheelRadius: %f", pVesselCollDef->backWheelRadius);

	oapiWriteLogV("FrontWheelHalfWidth: %f", pVesselCollDef->frontWheelHalfWidth);	 // actual width is 2.364(twice)
	oapiWriteLogV("BackWheelHalfWidth: %f", pVesselCollDef->backWheelHalfWidth);	 // actual width is 2.364(twice)

	oapiWriteLogV("FrontWheelFriction: %f", pVesselCollDef->frontWheelFriction);
	oapiWriteLogV("BackWheelFriction: %f", pVesselCollDef->backWheelFriction);

	// Skip indexes, wheel direction and axle - these are not changeable
	// Connection height is also not changeable for now

	// Suspension parameters
	oapiWriteLogV("FrontSuspensionStiffness: %f", pVesselCollDef->frontSuspensionStiffness);
	oapiWriteLogV("FrontSuspensionDamping: %f", pVesselCollDef->frontSuspensionDamping);  //this may need to be increased for the DG
	oapiWriteLogV("FrontSuspensionCompression: %f", pVesselCollDef->frontSuspensionCompression);
	oapiWriteLogV("FrontSuspensionRestLength: %f", pVesselCollDef->frontSuspensionRestLength);

	oapiWriteLogV("BackSuspensionStiffness: %f", pVesselCollDef->backSuspensionStiffness);
	oapiWriteLogV("BackSuspensionDamping: %f", pVesselCollDef->backSuspensionDamping);  //this may need to be increased for the DG
	oapiWriteLogV("BackSuspensionCompression: %f", pVesselCollDef->backSuspensionCompression);
	oapiWriteLogV("BackSuspensionRestLength: %f", pVesselCollDef->backSuspensionRestLength);

	oapiWriteLogV("RollInfluence: %f", pVesselCollDef->rollInfluence);

	// Orbiter animation info
	oapiWriteLogV("Number of Wheels: %d", pVesselCollDef->numWheels);
	oapiWriteLogV("WheelMeshIndex : %d", pVesselCollDef->wheelMeshIndex);

	// It is mandatory to supply all wheel info, these flags help to check this
	for (int i = 0; i < pVesselCollDef->numWheels; ++i) {
		oapiWriteLogV("Wheel : %d ", i);
		oapiWriteLogV("WheelMeshGroupCenter : %f, %f, %f", V3ARGS(pVesselCollDef->wheelMeshGroupCenter[i]));
		oapiWriteLogV("WheelMeshGroupIndex: %f", pVesselCollDef->wheelMeshGroupIndex[i]);
		oapiWriteLogV("WheelStrutMeshGroupIndex: %f", pVesselCollDef->wheelStrutMeshGroupIndex[i]);
		oapiWriteLogV("isWheelInfoSet : %d ", pVesselCollDef->isWheelInfoSet[i]);
	}



	// Iterate through all shapes in compound shape


}


/**
 * Loads a MSH mesh based collision shape as a btConvexHullShape
 * Also puts the .msh fileName in the btCollisionShape as a user pointer.
 *
 */
int
Bump_VesselCollisionDefCache::loadMsh(char *fileName, btConvexHullShape *convexHull)
{
	// Mesh must not have .msh at end, relative path must be mentioned
	char extendedFileName[256];
	strcpy (extendedFileName, "Meshes/");
	strcat (extendedFileName, fileName);
	strcat (extendedFileName, ".msh");

	FILE *file;
	if ((file = fopen(extendedFileName, "r")) == NULL)	{
		oapiWriteLogV("Bump_CollisionMSH::loadMsh: ERROR Could not open file %s", fileName);
		return 1;
	}
	else
		fclose(file);

	// Mesh file exists, we can open it now
	MESHHANDLE hMesh = oapiLoadMesh(fileName);

	int numVertices;

	if (hMesh) {

		int  c = oapiMeshGroupCount (hMesh);

		// Add check for last group here

		// Only import 1st group
		MESHGROUP* mshGrp =  oapiMeshGroup(hMesh, 0);

		if (mshGrp->nVtx > MAX_VERTICES) {
			numVertices = MAX_VERTICES;
			oapiWriteLogV("Bump_CollisionMSH::load: Max vertices (%d) exceeded %d. \
					Rounded to %d vertices for file %s",
					mshGrp->nVtx, MAX_VERTICES, MAX_VERTICES, fileName);
		}
		else
			numVertices = mshGrp->nVtx;


		for (int i = 0; i < numVertices; i++ ) {
			/*oapiWriteLogV("Vertex : %3d : (%f, %f, %f)", i,
					mshGrp->Vtx[i].x, mshGrp->Vtx[i].y, mshGrp->Vtx[i].z );*/

			// Convex hull shape makes a copy of the point, so we do not need to maintain a list
			convexHull->addPoint(btVector3(mshGrp->Vtx[i].x, mshGrp->Vtx[i].y, mshGrp->Vtx[i].z));
		}
	}
	else {
		oapiWriteLogV("Bump_CollisionMSH::load: ERROR Could not load mesh %s", fileName);
		return 2;
	}


	// Delete the Orbiter mesh
	oapiDeleteMesh(hMesh);

	return 0;
}

// Utility to vaidate upto 9 parameters, 1st 6 are position and orientation
inline bool
Bump_VesselCollisionDefCache::isValid(float x, float y, float z, float rx, float ry, float rz,
			   float p1, float p2, float p3)
{

	if (x > Bump_BulletBase::BULLET_WORLD_SIZE ||
		y > Bump_BulletBase::BULLET_WORLD_SIZE ||
		z > Bump_BulletBase::BULLET_WORLD_SIZE ) {

		oapiWriteLogV("Bump_VesselCollisionDefCache:isValid: One of the translation parameters is "
				"wrong : %f, %f, %f", x, y, z);
		return false;
	}

	if (rx > Bump_BulletBase::BULLET_WORLD_SIZE ||
		ry > Bump_BulletBase::BULLET_WORLD_SIZE ||
		rz > Bump_BulletBase::BULLET_WORLD_SIZE ) {

		oapiWriteLogV("Bump_VesselCollisionDefCache:isValid: One of the rotation parameters is "
				"wrong : %f, %f, %f", rx, ry, rz);
		return false;
	}

	if (p1 > Bump_BulletBase::BULLET_WORLD_SIZE || p1 < 0 ||
		p2 > Bump_BulletBase::BULLET_WORLD_SIZE || p2 < 0 ||
		p3 > Bump_BulletBase::BULLET_WORLD_SIZE || p3 < 0 ) {

		oapiWriteLogV("Bump_VesselCollisionDefCache:isValid: One of the extra shape parameters is "
				"wrong : %f, %f, %f", p1, p2, p3);
		return false;
	}


	return true;
}

